<?php

namespace eqphp;

class system{

    //解析配置文件
    static function config($name, $is_module = false){
        $config = 'data/config/';
        $module_path = '';
        if ($is_module) {
            $config = 'config/';
            $module_path = 'module/' . MODULE_NAME . '/';
        }
        if (preg_match('/^(local|test|mirror|product)$/', ENVIRONMENT)) {
            $config .= ENVIRONMENT . '/';
        }

        //计算绝对路径
        $name = explode('.', $name);
        $file_name = PATH_ROOT . $module_path .$config . array_shift($name) . '.php';

        //环境的覆盖公共的
        if (!is_file($file_name)) {
            $file_name = str_replace('/' . ENVIRONMENT . '/', '/', $file_name);
            if (!is_file($file_name)) {
                return null;
            }
        }

        //全局变量
        $key = md5($file_name);
        if (empty($GLOBALS['_CONFIG'][$key])) {
            $GLOBALS['_CONFIG'][$key] = include($file_name);
        }
        return util::array_get($GLOBALS['_CONFIG'][$key], $name);
    }

    //初始化系统变量
    static function init(){
        //设置错误提示
        $state = self::config('system.state');
        register_shutdown_function('eqphp\system::save_log');
        register_shutdown_function('eqphp\system::process_error');
        //error_reporting($state['error_switch'] ? E_ALL|E_STRICT : 0);

        //设置时区
        ini_set('date.timezone', $state['timezone']);

        //mongoDB设置
        //ini_set('mongo.long_as_object',true);

        //session设置
        $session = (object)self::config('session');
        session_name($session->name);
        ini_set('session.cookie_httponly', $session->mode);
        ini_set('session.save_handler',$session->storage);
        session_save_path($session->path);
        //open,close,read,write,destroy,gc
        //session_set_save_handler(with('ds'),true);
        //ini_set('session.gc_maxlifetime',$session->expire);
        //ini_set('session.cookie_lifetime',$session->expire);
        session_start();

        if (defined('RUN_MODE') && RUN_MODE === 'web') {
            self::web_init();
        }
    }

    //web服务初始化
    static private function web_init(){
        $message = 'forbid host [';
        $domain = self::config('system.domain');
        list($scheme, $port, $uri) = array('http', $domain['default'][2], '');
        if (isset($_SERVER['HTTP_HOST']) && isset($_SERVER['SERVER_PORT'])) {
            if (in_array($_SERVER['HTTP_HOST'], $domain['allow_host'], true)) {
                $host = $_SERVER['HTTP_HOST'];
            } else {
                $message .= $_SERVER['HTTP_HOST'];
            }
        }
        if (!isset($host)) {
            $message .= '] in config.system';
            logger::Exception('route', $message);
            throw new Exception($message, 100);
        }

        $port = in_array($port, array('80', '443'), true) ? '' : ':' . $port;
        if ($_SERVER['SERVER_PORT'] === '443') {
            $scheme = 'https';
        }

        if (isset($_SERVER['REQUEST_URI'])) {
            $uri = $_SERVER['REQUEST_URI'];
        }

        define('SITE_DOMAIN', $host);
        define('URL_REQUEST', trim($uri, '/'));
        define('U_R_L', $scheme . '://' . $host . $port . '/');
        define('URL_URI', U_R_L . URL_REQUEST);

        //定义当前运行模块名
        $module = self::config('system.module');
        if ($module['subdomain'] && is_array($module['subdomain'])) {
            foreach ($module['subdomain'] as $subdomain) {
                if (strpos($host, $subdomain . '.') !== false) {
                    define('SUBDOMAIN', $subdomain);
                    return define('MODULE_NAME', $subdomain);
                }
            }
        }
        $current_module = current(explode('/', trim($_SERVER['REQUEST_URI'], '/')));
        if (is_array($module['list']) && in_array($current_module, $module['list'], true)) {
            define('MODULE_NAME', $current_module);
        }
    }

    //解析路由
    static private function parse_route($root_lie = 0){
        $is_module = false;
        $space_name = 'common';
        $module = $segment = input::url($root_lie);
        if (defined('MODULE_NAME') || defined('SUBDOMAIN')) {
            $is_module = true;
            $module = MODULE_NAME;
            $space_name = MODULE_NAME;
            if ($module === $segment) {
                $root_lie += 1;
                $segment = input::url($root_lie);
            }
        }

        if (self::config('system.state.config_route')) {
            $route = self::config('route');
            if ($is_module && isset($route[$module][$segment])) {
                return explode('::', $route[$module][$segment]);
            }
            if (isset($route[$segment]) && is_string($route[$segment]) && strpos($route[$segment], '::')) {
                return explode('::', $route[$module]);
            }
        }

        $suffix = '';
        $prefix = $space_name . '\action\\';
        if (empty($segment) || preg_match('/^[1-9]\d*$/', $segment)) {
            $action_name = $module ? $module : 'index';
            return array($prefix . $action_name . $suffix, 'index');
        }

        $controller = $prefix . $segment . $suffix;
        $method = trim(input::url($root_lie + 1));
        if (class_exists($controller)) {
            if ($method && method_exists($controller, $method)) {
                return array($controller, $method);
            }
            if (method_exists($controller, '__call')) {
                return array($controller, '__call');
            }
            if (method_exists($controller, '__callStatic')) {
                return array($controller, '__callStatic');
            }
            if (method_exists($controller, 'index')) {
                return array($controller, 'index');
            }
        }
        $message = $controller . '.' . $method . ' parse fail';
        logger::Exception('route', $message);
        throw new Exception($message, 101);
    }

    //动态调用、执行
    static function bootstrap(){
        try {
            self::init();
            list($controller, $method) = self::parse_route();
            define('CURRENT_ACTION', $controller . ':' . $method);
            if (property_exists($controller, 'static_class')) {
                if (method_exists($controller, '__before')) {
                    call_user_func($controller . '::__before');
                }
                call_user_func(array($controller, $method), explode('/', URL_REQUEST));
                if (method_exists($controller, '__after')) {
                    call_user_func($controller . '::__after');
                }
            } else {
                $object = new $controller;
                if (method_exists($controller, '__before')) {
                    call_user_func(array($object, '__before'));
                }
                call_user_func_array(array($object, $method), array(explode('/', URL_REQUEST)));
                if (method_exists($controller, '__after')) {
                    call_user_func(array($object, '__after'));
                }
            }
        } catch (Exception $e) {
            if (!in_array($e->getCode(), array(100, 101, 102, 103), true)) {
                logger::exception('error', $e->getCode() . ' : ' . $e->getMessage());
            }

            if (in_array(ENVIRONMENT, array('mirror', 'product'), true)) {
				
                if (http::is_ajax()) {
                    http::json(array('error' => 6, 'message' => $e->getMessage()));
                }
                http::redirect('abort/404');
            }
            self::exception($e);
        }
    }



    //处理错误
    static function process_error(){
        $error = (object)error_get_last();
        if ($error && isset($error->type)) {
            ob_end_clean();
            $error->type = util::meta('error.' . $error->type);
            $log_data = $error->type . ' : ' . $error->message . ' [' . $error->file . ' ' . $error->line . ']';
            logger::exception('error', $log_data);
            self::save_log();

            if (defined('RUN_MODE') && RUN_MODE === 'cli') {
                exit($log_data);
            }

            if (in_array(ENVIRONMENT, array('mirror', 'product'), true)) {
                if (http::is_ajax()) {
                    http::json(array('error' => 7, 'message' => $error->message));
                }
                http::redirect('abort/500');
            }

            header('Content-Type:text/html; charset=utf-8');
            $html = '<link rel="stylesheet" type="text/css" href="/file/static/reset.css">';
            $html .= '<div class="trace"><pre><h5><b>%s</b>%s</h5><h6>%s<b>%d</b></h6></pre></div>';
            exit(sprintf($html, $error->type, $error->message, $error->file, $error->line));
        }
    }

    //写入日志
    static function save_log(){
        if (isset($GLOBALS['_LOG']) && is_array($GLOBALS['_LOG'])) {
            foreach ($GLOBALS['_LOG'] as $key => $string) {
                file_put_contents($key, implode('', $string), FILE_APPEND);
                unset($GLOBALS['_LOG'][$key]);
            }
        }
    }

    //输出异常追溯信息
    static function exception(Exception $e){
        $html = '<link rel="stylesheet" type="text/css" href="/file/static/reset.css">';
        $html .= '<div class="trace"><pre>';
        $html .= '<h5><b>' . $e->getCode() . '</b>' . $e->getMessage() . '</h5>';
        $html .= '<h6>' . $e->getFile() . '<b>' . $e->getLine() . '</b></h6>';
        foreach ($e->getTrace() as $trace) {
            $trace = (object)$trace;
            $html .= '<h6>' . (isset($trace->file) ? $trace->file : '');
            $html .= isset($trace->line) ? '<b>' . $trace->line . '</b>' : '';
            $html .= isset($trace->class) ? $trace->class : '';
            $html .= isset($trace->type) ? $trace->type : '';
            $html .= (isset($trace->function) ? $trace->function : '') . '</h6>';
            if (isset($trace->args) && $trace->args) {
                $html .= '<p>' . print_r($trace->args, true) . '</p>';
            }
        }
        header('Content-Type:text/html; charset=utf-8');
        echo $html . '</pre></div>';
    }

}